﻿
//-------------------------------------------------------------------------------
// <copyright file="SwfObject.cs" company="GrannetDotNet Software">
//     Copyright © 2009 GrannetDotNet Software. All rights reserved.
// </copyright>
// <author>Grant Harmeyer</author>
//-------------------------------------------------------------------------------

namespace GrannetDotNet.Web.UI.WebControls
{
    using System;
    using System.ComponentModel;
    using System.Configuration;
    using System.Drawing;
    using System.Globalization;
    using System.Text;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;

    /// <summary>
    /// Control used to embed SWFObject enabled Flash movies in a Page.
    /// </summary>
    /// <example>    
    /// <para>
    /// Example #1: Add an SwfObject control to a Page using markup.
    /// </para>
    /// <code>
    ///&lt;gdn:SwfObject       
    ///  ID="swfObj1"
    ///  AllowScriptAccess="Always" 
    ///  BaseUrl="~/App_Support/Flash/"
    ///  runat="server"
    ///  MovieUrl="~/App_Support/Flash/player.swf" 
    ///  Height="200px" 
    ///  Width="328px"    
    ///  UseDynamicPublishing="false"
    ///  UseExpressInstallation="true"&gt;
    ///  &lt;FlashVars&gt;
    ///    &lt;gdn:FlashVar Name="file" Value="video.flv"/&gt;
    ///    &lt;gdn:FlashVar Name="image" Value="preview.jpg"/&gt;        
    ///  &lt;/FlashVars&gt;
    ///  &lt;AlternateContentTemplate&gt;
    ///    &lt;p&gt;&lt;a href="http://get.adobe.com/flashplayer"&gt;Get Flash&lt;/a&gt; to see this player.&lt;/p&gt;        
    ///  &lt;/AlternateContentTemplate&gt;
    ///&lt;/gdn:SwfObject&gt;
    /// </code>    
    /// <para>
    /// Example #2: Add an SwfObject control to a Page using managed code.
    /// </para>  
    /// <code>
    /// SwfObject                 swfObj1        = null;
    /// SwfObjectAlternateContent swfObjContent1 = null;    
    /// 
    /// /* Create SwfObject control */
    /// swfObj1                          = new SwfObject();
    /// swfObj1.ID                       = &quot;swfObj1&quot;;
    /// swfObj1.AllowScriptAccess        = SwfScriptAccess.Always;
    /// swfObj1.BaseUrl                  = &quot;~/App_Support/Flash/&quot;;
    /// swfObj1.MovieUrl                 = &quot;~/App_Support/Flash/player.swf&quot;;
    /// swfObj1.Height                   = Unit.Parse(&quot;200px&quot;);
    /// swfObj1.Width                    = Unit.Parse(&quot;328px&quot;);        
    /// swfObj1.UseDynamicPublishing     = false;
    /// swfObj1.UseExpressInstallation   = true;
    /// 
    /// /* Add FlashVars */
    /// swfObj1.FlashVars.Add(new FlashVar(&quot;file&quot;, &quot;video.flv&quot;));
    /// swfObj1.FlashVars.Add(new FlashVar { Name = &quot;image&quot;, Value = &quot;preview.jpg&quot; });
    /// 
    /// /* Create Alternate Content Template */
    /// swfObjContent1                   = new SwfObjectAlternateContent();
    /// swfObjContent1.Controls.Add(new LiteralControl(&quot;&lt;p&gt;&lt;a href=\&quot;http://get.adobe.com/flashplayer\&quot;&gt;Get Flash&lt;/a&gt; to see this player.&lt;/p&gt;&quot;));
    /// swfObj1.AlternateContentTemplate = swfObjContent1;
    /// 
    /// /* Add the SwfObject to a PlaceHolder on the Page */
    /// this.plchGdnSwfObject.Controls.Add(swfObj1);
    /// </code>
    /// </example>
    [Designer(typeof(SwfObjectDesigner)),
    ParseChildren(ChildrenAsProperties = true),
    ToolboxData("<{0}:SwfObject runat=server></{0}:SwfObject>")]
    public class SwfObject 
        : Control
    {
        #region [ Fields ]

        /* Fields */

        /// <summary>
        /// Nullable storage for the AllowFullScreen property.
        /// </summary>
        private bool? m_AllowFullScreen;

        /// <summary>
        /// Nullable storage used to determine whether or not to disable AutoHideShow in swfobject for Firefox 3+ support.
        /// </summary>
        private bool? m_AutoHideShow;

        /// <summary>
        /// Nullable storage for the DeviceFont property.
        /// </summary>
        private bool? m_DeviceFont;

        /// <summary>
        /// Nullable storage for the LoopVideo property.
        /// </summary>
        private bool? m_LoopVideo;

        /// <summary>
        /// Nullable storage for the PlayOnLoad property.
        /// </summary>
        private bool? m_PlayOnLoad;

        /// <summary>
        /// Nullable storage for the SeamlessTabbing property.
        /// </summary>
        private bool? m_SeamlessTabbing;

        /// <summary>
        /// Nullable storage for the ShowMenu property.
        /// </summary>
        private bool? m_ShowMenu;

        /// <summary>
        /// Nullable storage for the SwLiveConnect property.
        /// </summary>
        private bool? m_SwLiveConnect;

        /// <summary>
        /// Nullable storage for the UseDynamicPublishing property.
        /// </summary>
        private bool? m_UseDynamicPublishing;

        /// <summary>
        /// Nullable storage for the UseExpressInstallation property.
        /// </summary>
        private bool? m_UseExpressInstallation;

        /* Control Constants (Defaults) */        

        /// <summary>
        /// The default target Flash version for the control (9.0.0).
        /// </summary>
        private const string FLASH_VERSION = "9.0.0";

        /* Controls */

        /// <summary>
        /// Control used to define the alternate content template for the control.
        /// </summary>
        private SwfObjectAlternateContent swfAltContent;

        #endregion

        #region [ .ctors ]

        /// <summary>
        /// Creates a new instance of an SwfObject object.
        /// </summary>
        public SwfObject()
            : base()
        {
            /* Set Control Defaults */                        
            this.FlashVersion           = FLASH_VERSION;
            this.UseExpressInstallation = true;
            this.FlashVars              = new FlashVarCollection();
        }

        #endregion

        #region [ Events ]
        #endregion

        #region [ Properties ]

        /// <summary>
        /// Gets or sets a value indicating the alignment of the Flash movie.
        /// </summary>
        [Browsable(true),
        Category("Appearance"),
        Description("Alignment of the video. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute)]
        public SwfAlign Align
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets a value indicating whether or not the full screen mode is enabled.
        /// </summary>
        [Browsable(true),
        Category("Behavior"),
        Description("Whether or not to allow full screen mode for the movie. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute)]
        public bool AllowFullScreen
        {
            get
            {
                return (this.m_AllowFullScreen.HasValue) 
                            ? this.m_AllowFullScreen.Value 
                            : false;
            }
            set
            {                
                this.m_AllowFullScreen = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating the network settings for the Flash movie.
        /// </summary>
        [Browsable(true),
        Category("Behavior"),
        Description("Networking settings for the movie. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute)]
        public SwfAllowNetworking AllowNetworking
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets a value indicating the script access for the Flash movie.
        /// </summary>
        [Browsable(true),
        Category("Behavior"),
        Description("Script access setting for the movie. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute)]
        public SwfScriptAccess AllowScriptAccess
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the alternate content template for the underlying swfobject.
        /// </summary>        
        [Browsable(false),
        PersistenceMode(PersistenceMode.InnerProperty),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        TemplateContainer(typeof(SwfObjectAlternateContent))]
        public ITemplate AlternateContentTemplate 
        { 
            get; 
            set; 
        }
        
        /// <summary>
        /// Gets or sets a value indicating whether or not to disable AutoHideShow in swfobject for Firefox 3+ support.
        /// </summary>
        [Browsable(true),
        Category("Behavior"),
        DefaultValue(true),
        Description("Determine whether or not to disable AutoHideShow in swfobject for Firefox 3+ support."),
        PersistenceMode(PersistenceMode.Attribute)]
        public bool AutoHideShow
        {
            get
            {
                return (this.m_AutoHideShow.HasValue) 
                            ? this.m_AutoHideShow.Value 
                            : true;
            }
            set
            {
                this.m_AutoHideShow = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating the background color for the Flash object.
        /// </summary>
        [Browsable(true),
        Category("Appearance"),
        Description("Background color for the movie. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute)]
        public Color BackColor
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets a value indicating the background color for the Flash object.
        /// </summary>
        /// <remarks>
        /// This property is now obsolete. Use the BackColor property instead.
        /// </remarks>
        [Browsable(true),
        Category("Appearance"),
        Description("Background color for the movie. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute),
        Obsolete("This property is now obsolete. Use the BackColor property instead.")]
        public Color BackgroundColor
        {
            get
            {
                return this.BackColor;
            }
            set
            {
                this.BackColor = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating the base URL of the Flash movie (.swf file).
        /// </summary>
        [Browsable(true),
        Category("Behavior"),
        Description("The base URL (directory) for the movie and any related assets. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute), 
        UrlProperty()]
        public string BaseUrl
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets a reference to the callback function that is called on both success or failure of embedding a SWF file
        /// </summary>
        [Browsable(true),
        Category("Behavior"),
        Description("callback function that is called on both success or failure of embedding a SWF file. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute)]
        public string ClientCallback 
        { 
            get; 
            set; 
        }

        /// <summary>
        /// Gets or sets the CSS class for the control
        /// </summary>
        [Browsable(true),
        Category("Appearance"),
        Description("The CSS class that is applied to the <div /> tag that encapsulates the control."), 
        PersistenceMode(PersistenceMode.Attribute)]
        public string CssClass 
        { 
            get; 
            set; 
        }

        /// <summary>
        /// Gets or sets a value whether the movie should use the device's fonts, or the font's embedded in the movie.
        /// </summary>
        [Browsable(true),
        Category("Appearance"),
        Description("Font setting for the movie. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute)]
        public bool DeviceFont
        {
            get
            {
                return (this.m_DeviceFont.HasValue) 
                            ? this.m_DeviceFont.Value 
                            : false;
            }
            set
            {
                this.m_DeviceFont = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating the URL to the express installation movie.
        /// </summary>
        /// <remarks>
        /// If this property is not set, the control will default to using the URL of the embedded express installation file.
        /// </remarks>
        [Browsable(true),
        Category("Behavior"),
        Description("The URL to the express installation movie. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute),
        UrlProperty()]
        public string ExpressInstallUrl
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets a value indicating the collection of input variables for the movie.
        /// </summary>
        [Browsable(false),
        Category("Behavior"),
        Description("The variables to be passed into the movie using the flashvars parameter. This property is optional."),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        PersistenceMode(PersistenceMode.InnerProperty)]
        public FlashVarCollection FlashVars 
        { 
            get; 
            set; 
        }

        /// <summary>
        /// Gets or sets a value indicating the target version of the Flash player.
        /// </summary>
        [Browsable(true),
        Category("Behavior"),
        DefaultValue(FLASH_VERSION),
        Description("The version of Flash player to use on the client. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute)]
        public string FlashVersion 
        { 
            get; 
            set; 
        }

        /// <summary>
        /// Gets or sets a value indicating the height of the movie.
        /// </summary>
        [Browsable(true), 
        Category("Layout"),
        Description("The height for the movie. This property is required."),
        PersistenceMode(PersistenceMode.Attribute)]
        public Unit Height 
        { 
            get; 
            set; 
        }

        /// <summary>
        /// Gets or sets a value whether the movie repeats indefinitely or stops when it reaches the last frame.
        /// </summary>
        [Browsable(true),
        Category("Behavior"),
        Description("Whether or not to loop the movie. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute)]
        public bool LoopVideo 
        {
            get
            {
                return (this.m_LoopVideo.HasValue) 
                            ? this.m_LoopVideo.Value 
                            : false;
            }
            set
            {
                this.m_LoopVideo = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating the window mode for the Flash video.
        /// </summary>
        /// <remarks>
        /// This property is now obsolete. Use the WindowMode property instead.
        /// </remarks>
        [Browsable(true),
        Category("Appearance"),
        Description("The window mode for the movie. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute), 
        Obsolete("This property is now obsolete. Use the WindowMode property instead.")]
        public SwfWMode Mode
        {
            get
            {
                return this.WindowMode;
            }
            set
            {
                this.WindowMode = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating the URL to the movie.
        /// </summary>
        [Browsable(true),
        Category("Movie"),
        Description("The URL to the movie (.swf) file. This property is required."),
        PersistenceMode(PersistenceMode.Attribute), 
        UrlProperty()]
        public string MovieUrl 
        { 
            get; 
            set; 
        }

        /// <summary>
        /// Gets or sets a value indicating whether the Flash movie begins playing immediately upon loading in the browser.
        /// </summary>
        [Bindable(true), 
        Browsable(true),
        Category("Behavior"),
        Description("Whether or not to start playing the movie when the page loads. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute)]
        public bool PlayOnLoad 
        {
            get
            {
                return (this.m_PlayOnLoad.HasValue) 
                            ? this.m_PlayOnLoad.Value 
                            : false;
            }
            set
            {
                this.m_PlayOnLoad = value;
            }
        }

        /// <summary>
        /// Gets or sets a value for the specified quality of the Flash movie.
        /// </summary>
        [Browsable(true),
        Category("Behavior"),
        Description("The quality setting for the movie. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute)]
        public SwfQuality Quality
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets a value indicating the alignment of the Flash video.
        /// </summary>
        [Browsable(true),
        Category("Appearance"),
        Description("Alignment setting for the movie. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute)]
        public SwfScaledAlignment ScaledAlignment
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets a value indicating the alignment of the Flash video.
        /// </summary>
        /// <remarks>
        /// This property is now obsolete. Use the ScaledAlignment property instead.
        /// </remarks>
        [Browsable(true),
        Category("Appearance"),
        Description("Alignment setting for the movie. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute),
        Obsolete("This property is now obsolete. Use the ScaledAlignment property instead.")]
        public SwfScaledAlignment SAlign
        {
            get
            {
                return this.ScaledAlignment;
            }
            set
            {
                this.ScaledAlignment = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating the scale for the Flash movie.
        /// </summary>
        [Browsable(true),
        Category("Appearance"),
        Description("Scale setting for the movie. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute)]
        public SwfScale Scale 
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets a value indicating whether or not to use seamless tabbing.
        /// </summary>
        [Browsable(true),
        Category("Behavior"),
        Description("Tabbing setting for the movie. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute)]
        public bool SeamlessTabbing
        {
            get
            {
                return (this.m_SeamlessTabbing.HasValue) 
                            ? this.m_SeamlessTabbing.Value 
                            : false;
            }
            set
            {
                this.m_SeamlessTabbing = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the menu for the player should be shown.
        /// </summary>
        [Browsable(true),
        Category("Behavior"),
        Description("Whether or not to show the Flash menu on the movie. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute)]
        public bool ShowMenu 
        {
            get
            {
                return (this.m_ShowMenu.HasValue)
                            ? this.m_ShowMenu.Value
                            : false;
            }
            set
            {
                this.m_ShowMenu = value;
            } 
        }
        
        /// <summary>
        /// Gets or sets a value indicating the URL to the SWFObject script library.
        /// </summary>
        /// <remarks>
        /// If this property is not set, the control will default to using the URL of the embedded SWFObject script library (version 2.1).
        /// </remarks>
        [Browsable(true),
        Category("Behavior"),
        Description("The URL to the SWFObject script library. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute),
        UrlProperty()]
        public string SwfScriptUrl
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets a value indicating whether the browser should start Java when loading the Flash Player for the first time.
        /// </summary>
        [Browsable(true),
        Category("Behavior"),
        Description("The Live Connect setting for the movie. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute)]
        public bool SwLiveConnect 
        {
            get
            {
                return (this.m_SwLiveConnect.HasValue)
                            ? this.m_SwLiveConnect.Value
                            : false;
            }
            set
            {
                this.m_SwLiveConnect = value;
            } 
        }

        /// <summary>
        /// Gets or sets a value indicating if dynamic publishing will be used for rendering.
        /// </summary>
        [Browsable(true),
        Category("Behavior"),
        DefaultValue(false),
        Description("Whether or not to use SWFObject dymanic publishing. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute)]
        public bool UseDynamicPublishing 
        {
            get
            {
                return (this.m_UseDynamicPublishing.HasValue)
                            ? this.m_UseDynamicPublishing.Value
                            : false;
            }
            set
            {
                this.m_UseDynamicPublishing = value;
            }  
        }

        /// <summary>
        /// Gets or sets a value indicating whether or not to use express installation.
        /// </summary>
        [Browsable(true),
        Category("Behavior"),
        DefaultValue(true),
        Description("Whether or not to use SWFObject express installation. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute)]
        public bool UseExpressInstallation
        {
            get
            {
                return (this.m_UseExpressInstallation.HasValue)
                            ? this.m_UseExpressInstallation.Value
                            : false;
            }
            set
            {
                this.m_UseExpressInstallation = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating the width of the Flash movie.
        /// </summary>
        [Browsable(true),
        Category("Layout"),
        Description("The width for the movie. This property is required."),
        PersistenceMode(PersistenceMode.Attribute)]
        public Unit Width
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets a value indicating the window mode for the Flash video.
        /// </summary>
        [Browsable(true),
        Category("Appearance"),
        Description("The window mode for the movie. This property is optional."),
        PersistenceMode(PersistenceMode.Attribute)]
        public SwfWMode WindowMode
        {
            get;
            set;
        }

        #endregion

        #region [ Methods ]

        /// <summary>
        /// Creates instances of all child controls for the control
        /// </summary>
        protected override void CreateChildControls()
        {
            /* Clear Controls */
            base.Controls.Clear();
            base.CreateChildControls();

            /* Create Controls */
            this.swfAltContent    = new SwfObjectAlternateContent();
            this.swfAltContent.ID = "AlternateContent";
            this.Controls.Add(this.swfAltContent);
        }

        /// <summary>
        /// Obtains the attributes of the control as a JSON string for dynamic publishing
        /// </summary>
        /// <returns>The JSON representation of the attributes.</returns>
        private string GetAttributesJson()
        {
            CommaDelimitedStringCollection attr = null;

            /* Add attributes */
            attr = new CommaDelimitedStringCollection();

            attr.Add(string.Format("id:\'{0}\'",        this.ClientID));
            attr.Add(string.Format("name:\'{0}\'",      this.ClientID));

            if (!string.IsNullOrEmpty(this.CssClass))
            {
                attr.Add(string.Format("styleclass:\'{0}\'", this.CssClass));
            }

            if (this.Align != default(SwfAlign))
            {
                attr.Add(string.Format("align:\'{0}\'", SwfEnum.Parse(this.Align)));
            }

            attr.Add(string.Format("width:\'{0:N0}\'",  this.Width.Value));
            attr.Add(string.Format("height:\'{0:N0}\'", this.Height.Value));           
            

            return attr.ToString();
        }

        /// <summary>
        /// Obtains the FlashVars collection as a JSON formatted string for dynamic publishing.
        /// </summary>
        /// <returns>The JSON representation of the FlashVars.</returns>
        private string GetFlashVarsJson()
        {
            CommaDelimitedStringCollection flashVars = null;

            /* Add FlashVars */
            flashVars = new CommaDelimitedStringCollection();

            foreach (FlashVar fv in this.FlashVars)
            {
                flashVars.Add(string.Format("{0}:\'{1}\'", fv.Name, fv.Value));
            }            

            return flashVars.ToString();
        }

        /// <summary>
        /// Obtains the parameters of the control as a JSON string for dynamic publishing.
        /// </summary>
        /// <returns>The JSON representation of the parameters.</returns>
        private string GetParametersJson()
        {
            CommaDelimitedStringCollection prms = null;

            /* Add Parameters */
            prms = new CommaDelimitedStringCollection();

            /* play */
            if (this.m_PlayOnLoad.HasValue)
            {
                prms.Add(string.Format(
                                    "play:\'{0}\'",
                                    this.m_PlayOnLoad.Value.ToString().ToLower()));
            }

            /* loop */
            if (this.m_LoopVideo.HasValue)
            {
                prms.Add(string.Format(
                                    "loop:\'{0}\'",
                                    this.m_LoopVideo.Value.ToString().ToLower()));
            }

            /* menu */
            if (this.m_ShowMenu.HasValue)
            {
                prms.Add(string.Format(
                                    "menu:\'{0}\'",
                                    this.m_ShowMenu.Value.ToString().ToLower()));
            }

            /* quality */
            if (this.Quality != default(SwfQuality))
            {
                prms.Add(string.Format(
                                    "quality:\'{0}\'",
                                    SwfEnum.Parse(this.Quality)));
            }

            /* scale */
            if (this.Scale != default(SwfScale))
            {
                prms.Add(string.Format(
                                    "scale:\'{0}\'",
                                    SwfEnum.Parse(this.Scale)));
            }

            /* salign */
            if (this.ScaledAlignment != default(SwfScaledAlignment))
            {
                prms.Add(string.Format(
                                    "salign:\'{0}\'",
                                    SwfEnum.Parse(this.ScaledAlignment)));
            }

            /* wmode */
            if (this.WindowMode != default(SwfWMode))
            {
                prms.Add(string.Format(
                                    "wmode:\'{0}\'",
                                    SwfEnum.Parse(this.WindowMode)));
            }

            /* bgcolor */
            if (this.BackColor != default(Color))
            {
                prms.Add(string.Format(
                                    "bgcolor:\'{0}\'",
                                    ColorTranslator.ToHtml(this.BackColor)));
            }

            /* base */
            if (!string.IsNullOrEmpty(this.BaseUrl))
            {
                prms.Add(string.Format(
                                    "base:\'{0}\'",
                                    this.MakeRelativeUrl(this.BaseUrl)));
            }

            /* swliveconnect */
            if (this.m_SwLiveConnect.HasValue)
            {
                prms.Add(string.Format(
                                    "scale:\'{0}\'",
                                    this.m_SwLiveConnect.Value.ToString().ToLower()));
            }

            /* devicefont */
            if (this.m_DeviceFont.HasValue)
            {
                prms.Add(string.Format(
                                    "devicefont:\'{0}\'",
                                    this.m_DeviceFont.Value.ToString().ToLower()));
            }     

            /* allowscriptaccess */
            if (this.AllowScriptAccess != default(SwfScriptAccess))
            {
                prms.Add(string.Format(
                                    "allowscriptaccess:\'{0}\'",
                                    SwfEnum.Parse(this.AllowScriptAccess)));
            }

            /* seamlesstabbing */
            if (this.m_SeamlessTabbing.HasValue)
            {
                prms.Add(string.Format(
                                    "seamlesstabbing:\'{0}\'",
                                    this.m_SeamlessTabbing.Value.ToString().ToLower()));
            }

            /* allowfullscreen */
            if (this.m_AllowFullScreen.HasValue)
            {
                prms.Add(string.Format(
                                    "allowfullscreen:\'{0}\'",
                                    this.m_AllowFullScreen.Value.ToString().ToLower()));
            }

            /* allownetworking */
            if (this.AllowNetworking != default(SwfAllowNetworking))
            {
                prms.Add(string.Format(
                                    "allownetworking:\'{0}\'",
                                    SwfEnum.Parse(this.AllowNetworking)));
            }                                                                            

            return prms.ToString();
        }

        /// <summary>
        /// Translates a rooted URL to an application relative URL. Used for pathing SwfObject dependent files
        /// </summary>
        /// <param name="baseUrl">The rooted URL for the file</param>
        /// <returns>The application relative URL to the file</returns>
        private string MakeRelativeUrl(string baseUrl)
        {
            CompareInfo cmp    = null;
            string      retVal = null;
            
            if (!string.IsNullOrEmpty(baseUrl))
            {
                /* Use string comparison to determine if the URl is external */
                cmp = CompareInfo.GetCompareInfo(CultureInfo.CurrentUICulture.LCID);

                if (!cmp.IsPrefix(baseUrl, "http") &&
                    !cmp.IsPrefix(baseUrl, "https"))
                {
                    retVal = (VirtualPathUtility.IsAppRelative(baseUrl))
                                ? VirtualPathUtility.MakeRelative(this.Page.Request.Path, baseUrl)
                                : baseUrl;
                }
                else
                {
                    retVal = baseUrl;
                }
            }

            return retVal;
        }

        /// <summary>
        /// Method invoked when the PreRender event is raised.
        /// </summary>
        /// <param name="e">Data associated with the raising of the event.</param>
        protected override void OnPreRender(EventArgs e)
        {              
            /* Invoke Base */
            base.OnPreRender(e);

            /* PRECONTRACT: If there is no movie, do not register the scripts */
            if (string.IsNullOrEmpty(this.MovieUrl))
            {
                return;
            }

            /* SwfScriptUrl */
            if (string.IsNullOrEmpty(this.SwfScriptUrl))
            {
                this.SwfScriptUrl = this.Page.ClientScript.GetWebResourceUrl(
                                                                    this.GetType(),
                                                                    "GrannetDotNet.Web.UI.WebControls.Support.SwfObject.swfobject_2_2.js");
            }
            else
            {
                this.SwfScriptUrl = this.MakeRelativeUrl(this.SwfScriptUrl);
            }

            /* ExpressInstallUrl */
            if (string.IsNullOrEmpty(this.ExpressInstallUrl))
            {
                this.ExpressInstallUrl = this.Page.ClientScript.GetWebResourceUrl(
                                                                    this.GetType(),
                                                                    "GrannetDotNet.Web.UI.WebControls.Support.SwfObject.expressInstall.swf");
            }
            else
            {
                this.ExpressInstallUrl = this.MakeRelativeUrl(this.ExpressInstallUrl);
            }

            /* Register the script library */
            this.Page.ClientScript.RegisterClientScriptInclude("SwfObject", this.SwfScriptUrl);

            /* Register the client side script block */
            if (this.UseDynamicPublishing)
            {
                this.RegisterDynamicPublishingScriptBlock();
            }
            else
            {
                this.RegisterStaticPublishingScriptBlock();
            }
        }

        /// <summary>
        /// Registers the script block for dynamic publishing.
        /// </summary>
        private void RegisterDynamicPublishingScriptBlock()
        {
            StringBuilder                  sbScript = null;
            ClientScriptManager            csm      = this.Page.ClientScript;
            CommaDelimitedStringCollection args     = null;

            sbScript = new StringBuilder();
            sbScript.AppendFormat("var {0}_flashvars = {{{1}}};\n",    this.ClientID, this.GetFlashVarsJson());
            sbScript.AppendFormat("var {0}_params = {{{1}}};\n",       this.ClientID, this.GetParametersJson());
            sbScript.AppendFormat("var {0}_attributes = {{{1}}};\n\n", this.ClientID, this.GetAttributesJson());

            /* Prepare argument list */
            args     = new CommaDelimitedStringCollection();

            args.Add(string.Format("\'{0}\'",        this.MakeRelativeUrl(this.MovieUrl)));
            args.Add(string.Format("\'{0}\'",        this.ClientID));
            args.Add(string.Format("\'{0:N0}\'",     this.Width.Value));
            args.Add(string.Format("\'{0:N0}\'",     this.Height.Value));
            args.Add(string.Format("\'{0}\'",        this.FlashVersion));

            if (this.UseExpressInstallation)
            {
                args.Add(string.Format("\'{0}\'", this.ExpressInstallUrl));
            }
            else
            {
                args.Add("\'null\'");
            }

            args.Add(string.Format("{0}_flashvars",  this.ClientID));
            args.Add(string.Format("{0}_params",     this.ClientID));
            args.Add(string.Format("{0}_attributes", this.ClientID));

            if (!string.IsNullOrEmpty(this.ClientCallback))
            {
                args.Add(this.ClientCallback);
            }

            /* Prepare Script Block */
            if (!this.AutoHideShow)
            {
                sbScript.AppendLine("swfobject.switchOffAutoHideShow();");
            }
            sbScript.AppendFormat("swfobject.embedSWF({0});\n", args.ToString());

            /* Register Script Block */
            csm.RegisterStartupScript(
                            this.Page.GetType(),
                            string.Format("{0}_SwfObject", 
                            this.ClientID), 
                            sbScript.ToString(), 
                            true);
        }

        /// <summary>
        /// Registers the script block for static publishing.
        /// </summary>
        private void RegisterStaticPublishingScriptBlock()
        {
            StringBuilder                  sbScript = null;
            ClientScriptManager            csm      = this.Page.ClientScript;
            CommaDelimitedStringCollection args     = null;

            /* Prepare argument list */
            args = new CommaDelimitedStringCollection();

            args.Add(string.Format("\'{0}\'", this.ClientID));
            args.Add(string.Format("\'{0}\'", this.FlashVersion));

            if (this.UseExpressInstallation)
            {
                args.Add(string.Format("\'{0}\'", this.ExpressInstallUrl));
            }
            else
            {
                args.Add("null");
            }

            if (!string.IsNullOrEmpty(this.ClientCallback))
            {
                args.Add(this.ClientCallback);
            }

            /* Prepare Script Block */
            sbScript = new StringBuilder();

            if (!this.AutoHideShow)
            {
                sbScript.AppendLine("swfobject.switchOffAutoHideShow();");
            }
            sbScript.AppendFormat("swfobject.registerObject({0});\n", args.ToString());

            /* Register Script Block */
            csm.RegisterStartupScript(
                            this.Page.GetType(), 
                            string.Format("{0}_SwfObject", this.ClientID),
                            sbScript.ToString(),
                            true);
        }

        /// <summary>
        /// Renders the alternate content template.
        /// </summary>
        /// <param name="writer">The HtmlTextWriter object used to render the alternate content template.</param>
        protected virtual void RenderAlternateContent(HtmlTextWriter writer)
        {
            if (this.AlternateContentTemplate != null)
            {
                this.AlternateContentTemplate.InstantiateIn(this.swfAltContent);
                this.swfAltContent.RenderControl(writer);
            }
        }

        /// <summary>
        /// Renders the contents of the control to the Page.
        /// </summary>
        /// <param name="writer">The HtmlTextWriter used to render the control.</param>
        protected override void Render(HtmlTextWriter writer)
        {
            /* PRECONTRACT: If there is no movie, do not render the player */
            if (string.IsNullOrEmpty(this.MovieUrl))
            {
                return;
            }

            if (this.UseDynamicPublishing)
            {
                this.RenderDynamic(writer);
            }
            else
            {
                this.RenderStatic(writer);
            }
        }

        /// <summary>
        /// Renders the control for dynamic publishing.
        /// </summary>
        /// <param name="writer">The HtmlTextWriter used to render the control.</param>
        private void RenderDynamic(HtmlTextWriter writer)
        {
            writer.AddStyleAttribute(HtmlTextWriterStyle.Height, this.Height.ToString());
            writer.AddStyleAttribute(HtmlTextWriterStyle.Width,  this.Width.ToString());
            writer.AddAttribute(HtmlTextWriterAttribute.Id,      this.ClientID);
            writer.RenderBeginTag(HtmlTextWriterTag.Div); // <div id="">
            this.RenderAlternateContent(writer);
            writer.RenderEndTag();                        // </div>
        }        

        /// <summary>
        /// Renders the control for static publishing.
        /// </summary>
        /// <param name="writer">The HtmlTextWriter used to render the control.</param>
        private void RenderStatic(HtmlTextWriter writer)
        {              
            /* Render the control markup */
            if (this.Align != default(SwfAlign))
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Align, SwfEnum.Parse(this.Align));
            }

            if (!string.IsNullOrEmpty(this.CssClass))
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Class, this.CssClass);
            }
            writer.AddAttribute(HtmlTextWriterAttribute.Width,  Convert.ToInt32(this.Width.Value).ToString());
            writer.AddAttribute(HtmlTextWriterAttribute.Height, Convert.ToInt32(this.Height.Value).ToString());
            writer.AddAttribute("classid",                      "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000");
            writer.AddAttribute(HtmlTextWriterAttribute.Id,     this.ClientID);
            writer.AddAttribute(HtmlTextWriterAttribute.Name,   this.ClientID);
            writer.RenderBeginTag(HtmlTextWriterTag.Object);
            
            /* Render Params */

            /* movie */
            writer.Write(string.Format(
                                    "<param name=\"movie\" value=\"{0}\" />\n", 
                                    this.MakeRelativeUrl(this.MovieUrl)));

            this.RenderStaticParameters(writer);

            writer.Write("<!--[if !IE]>-->\n");

            /* Render Inner object */
            if (this.Align != default(SwfAlign))
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Align, SwfEnum.Parse(this.Align));
            }

            if (!string.IsNullOrEmpty(this.CssClass))
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Class, this.CssClass);
            }
            writer.AddAttribute(HtmlTextWriterAttribute.Width,  Convert.ToInt32(this.Width.Value).ToString());
            writer.AddAttribute(HtmlTextWriterAttribute.Height, Convert.ToInt32(this.Height.Value).ToString());
            writer.AddAttribute("data", this.MakeRelativeUrl(this.MovieUrl));
            writer.AddAttribute(HtmlTextWriterAttribute.Type, "application/x-shockwave-flash");
            writer.RenderBeginTag(HtmlTextWriterTag.Object);

            this.RenderStaticParameters(writer);

            writer.Write("<!--<![endif]-->\n");

            this.RenderAlternateContent(writer);

            writer.Write("<!--[if !IE]>-->\n");

            writer.RenderEndTag();
            
            writer.Write("<!--<![endif]-->\n");

            writer.RenderEndTag();
        }

        /// <summary>
        /// Renders the parameters for the object.
        /// </summary>
        private void RenderStaticParameters(HtmlTextWriter writer)
        {
            CommaDelimitedStringCollection flashVars = null;

            /* play */
            if (this.m_PlayOnLoad.HasValue)
            {
                this.WriteStaticParameter(
                            "play",
                            this.m_PlayOnLoad.Value.ToString().ToLower(),
                            writer);
            }

            /* loop */
            if (this.m_LoopVideo.HasValue)
            {
                this.WriteStaticParameter(
                            "loop",
                            this.m_LoopVideo.Value.ToString().ToLower(),
                            writer);
            }

            /* menu */
            if (this.m_ShowMenu.HasValue)
            {
                this.WriteStaticParameter(
                            "menu",
                            this.m_ShowMenu.Value.ToString().ToLower(),
                            writer);
            }

            /* quality */
            if (this.Quality != default(SwfQuality))
            {
                this.WriteStaticParameter(
                            "quality",
                            SwfEnum.Parse(this.Quality),
                            writer);
            }

            /* scale */
            if (this.Scale != default(SwfScale))
            {
                this.WriteStaticParameter(
                            "scale",
                            SwfEnum.Parse(this.Scale),
                            writer);
            }

            /* salign */
            if (this.ScaledAlignment != default(SwfScaledAlignment))
            {
                this.WriteStaticParameter(
                            "salign",
                            SwfEnum.Parse(this.ScaledAlignment),
                            writer);
            }

            /* wmode */
            if (this.WindowMode != default(SwfWMode))
            {
                this.WriteStaticParameter(
                            "wmode",
                            SwfEnum.Parse(this.WindowMode),
                            writer);
            }

            /* bgcolor */
            if (this.BackColor != default(Color))
            {
                this.WriteStaticParameter(
                            "bgcolor",
                            ColorTranslator.ToHtml(this.BackColor),
                            writer);
            }

            /* base */
            if (!string.IsNullOrEmpty(this.BaseUrl))
            {
                this.WriteStaticParameter(
                            "base",
                            this.MakeRelativeUrl(this.BaseUrl),
                            writer);
            }

            /* swliveconnect */
            if (this.m_SwLiveConnect.HasValue)
            {
                this.WriteStaticParameter(
                            "swliveconnect",
                            this.m_SwLiveConnect.Value.ToString().ToLower(),
                            writer);
            }

            /* flashvars */
            if (this.FlashVars.Count > 0)
            {
                flashVars = new CommaDelimitedStringCollection();

                foreach (FlashVar fv in this.FlashVars)
                {
                    flashVars.Add(string.Format(
                                            "{0}={1}",
                                            fv.Name,
                                            fv.Value));
                }

                this.WriteStaticParameter(
                            "flashvars",
                            flashVars.ToString().Replace(',', '&'),
                            writer);
            }  

            /* devicefont */
            if (this.m_DeviceFont.HasValue)
            {
                this.WriteStaticParameter(
                            "devicefont",
                            this.m_DeviceFont.Value.ToString().ToLower(),
                            writer);
            }

            /* allowscriptaccess */
            if (this.AllowScriptAccess != default(SwfScriptAccess))
            {
                this.WriteStaticParameter(
                            "allowscriptaccess",
                            SwfEnum.Parse(this.AllowScriptAccess),
                            writer);
            }

            /* seamlesstabbing */
            if (this.m_SeamlessTabbing.HasValue)
            {
                this.WriteStaticParameter(
                            "seamlesstabbing",
                            this.m_SeamlessTabbing.Value.ToString().ToLower(),
                            writer);
            }

            /* allowfullscreen */
            if (this.m_AllowFullScreen.HasValue)
            {
                this.WriteStaticParameter(
                            "allowfullscreen", 
                            this.m_AllowFullScreen.Value.ToString().ToLower(), 
                            writer);                
            }

            /* allownetworking */
            if (this.AllowNetworking != default(SwfAllowNetworking))
            {
                this.WriteStaticParameter(
                            "allownetworking", 
                            SwfEnum.Parse(this.AllowNetworking), 
                            writer);
            }                                                       
        }

        /// <summary>
        /// Renders a single paramater as a self-closing tag.
        /// </summary>
        /// <param name="name">The name of the parameter.</param>
        /// <param name="value">The value of the paramater.</param>
        /// <param name="writer">The HtmlTextWriter used to render the tag.</param>
        private void WriteStaticParameter(string name, string value, HtmlTextWriter writer)
        {
            writer.WriteBeginTag("param");
            writer.WriteAttribute("name", name);
            writer.WriteAttribute("value", value);
            writer.WriteLine(HtmlTextWriter.SelfClosingTagEnd);
        }

        #endregion
    }
}